// zip([1,2,3],[11,22],[111,222,333])
// => [ [ 1, 11, 111 ], [ 2, 22, 222 ] ]
export function zip(...arrays: any[]): any[] {
  if (arrays.length == 0) return []
  const shortest: any[] = arrays.reduce((a, b) => a.length < b.length ? a : b)
  return shortest.map((_, i) => arrays.map((array) => array[i]))
}

function zip1(...arrays: any[]): any[] {
  if (arrays.length == 0) return []
  const longest: any[] = arrays.reduce((a, b) => a.length > b.length ? a : b)
  return longest.map((_, i) => arrays.map((array) => array[i]))
}


// zip([1,2,3],[11,22],[111,222,333])
// => [ [ 1, 11, 111 ], [ 2, 22, 222 ], [ 3, undefined, 333 ] ]
export function zip2(...arrays: any[]): any[] {
  if (arrays.length == 0) return []
  return Array
    .apply(null, Array(arrays[0].length))
    .map((_, i) => arrays.map((array) => array[i]))
}

/**
 *
 * @param arrays
 * @example
 *
 *
 * zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
 *   return a + b + c;
 * });
 * // => [111, 222]
 */
export function zipWith(...arrays: any[]): any[] {
  const length = arrays.length
  const lastArg = length > 1 ? arrays[length - 1] : undefined
  let iteratee: any = undefined
  if (typeof lastArg === 'function') {
    iteratee = arrays.pop()
  }
  const zipArrays = zip(arrays)

  if (iteratee) {
    return zipArrays.map(array => iteratee.apply(null, array))
  } else {
    return zipArrays
  }
}

/**
 *
 * @param keys
 * @param values
 * @example
 *
 * zipObject(['a', 'b'], [1, 2]);
 * // => { 'a': 1, 'b': 2 }
 */
export function zipObject(keys: any[], values: any[]): object {
  if (keys == null || !keys.length) return {}
  const obj: any = {}
  for (let i = 0; i < keys.length; i++) {
    obj[keys[i]] = values[i]
  }
  return obj
}
